package com.derbysoft.lowcostadapter.dswitch2.translator.impl;

import com.derbysoft.lowcostadapter.commons.dto.*;
import com.derbysoft.lowcostadapter.commons.exception.InvalidFieldException;
import com.derbysoft.lowcostadapter.commons.exception.NotSupportedPaymentTypeException;
import com.derbysoft.lowcostadapter.commons.model.Hotel;
import com.derbysoft.lowcostadapter.commons.utils.DateTimeUtils;
import com.derbysoft.lowcostadapter.dswitch2.service.helper.Constant;
import com.derbysoft.lowcostadapter.dswitch2.translator.Translator;
import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.generic.constants.AgeQualifyingType;
import com.derbysoft.remote.dswitch.generic.constants.PhoneTechType;
import com.derbysoft.remote.dswitch.generic.constants.TransactionActionType;
import com.derbysoft.remote.dswitch.generic.constants.UniqueIDType;
import com.derbysoft.remote.dswitch.generic.dto.CustomerDTO;
import com.derbysoft.remote.dswitch.generic.dto.EmailDTO;
import com.derbysoft.remote.dswitch.generic.dto.TelephoneDTO;
import com.derbysoft.remote.dswitch.hotel.constants.PaymentType;
import com.derbysoft.remote.dswitch.hotel.dto.*;
import com.derbysoft.remote.share.Currency;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;

@Component("ds2HotelReservationRQTranslator")
public class HotelReservationRQTranslatorImpl extends AbstractRQTranslator implements Translator<GenericRQ<HotelReservationRQ>, Book, Hotel> {

    @Override
    public Book translate(GenericRQ<HotelReservationRQ> rq, Hotel hotel) {
        Book book = new Book();
        book.setBookRequest(createBookRequest(rq, hotel));
        return book;
    }

    private BookRequest createBookRequest(GenericRQ<HotelReservationRQ> rq, Hotel hotel) {
        HotelReservationRQ hotelReservationRQ = rq.getPayload();
        if (hotelReservationRQ.getResActionType() != TransactionActionType.BOOK) {
            throw new InvalidFieldException("resActionType", hotelReservationRQ.getResActionType().getValue());
        }

        BookRequest bookRequest = new BookRequest();
        bookRequest.setBookingDetails(createBookingDetails(hotelReservationRQ, hotel));
        bookRequest.setLoginDetails(createLoginDetails(rq.getHeader().getSource().getUniqueID().getId()));
        return bookRequest;
    }

    private BookingDetailsInfo createBookingDetails(HotelReservationRQ hotelReservationRQ, Hotel hotel) {
        HotelReservationDTO hotelReservationDTO = hotelReservationRQ.getHotelReservation();
        ReservationRoomStayDTO roomStayDTO = hotelReservationRQ.getHotelReservation().getRoomStays().get(0);

        if (roomStayDTO.getPaymentType() != PaymentType.PREPAY) {
            throw new NotSupportedPaymentTypeException(roomStayDTO.getPaymentType().name());
        }
        BookingDetailsInfo bookingDetailsInfo = new BookingDetailsInfo();
        bookingDetailsInfo.setTradeReference(
                findReservationID(hotelReservationRQ.getHotelReservationIDs(), UniqueIDType.TRAVEL_AGENCY));
        bookingDetailsInfo.setPropertyID(hotel.getPropertyID());
        bookingDetailsInfo.setArrivalDate(DateTimeUtils.formatDate(
                roomStayDTO.getStayDateRange().getCheckInDate()));
        bookingDetailsInfo.setDuration(roomStayDTO.getStayDateRange().lengthOfStay());
        bookingDetailsInfo.setRoomBookings(createRoomBookings(hotelReservationDTO));
        bookingDetailsInfo.setExpectedTotal(getTotal(roomStayDTO.getTotal()));


        CustomerDTO customerDTO = roomStayDTO.getGuests().get(0);
        if (StringUtils.isNotEmpty(customerDTO.getPersonName().getNameTitle())) {
            bookingDetailsInfo.setLeadGuestTitle(customerDTO.getPersonName().getNameTitle());
        } else {
            bookingDetailsInfo.setLeadGuestTitle(Constant.TITLE);
        }
        bookingDetailsInfo.setLeadGuestFirstName(customerDTO.getPersonName().getGivenName());
        bookingDetailsInfo.setLeadGuestLastName(customerDTO.getPersonName().getSurname());
        if (CollectionUtils.isNotEmpty(customerDTO.getAddresses())) {
            bookingDetailsInfo.setLeadGuestAddress1(customerDTO.getAddresses().get(0));
            if (customerDTO.getAddresses().size() > 1) {
                bookingDetailsInfo.setLeadGuestAddress2(customerDTO.getAddresses().get(1));
            }
        } else {
            bookingDetailsInfo.setLeadGuestAddress1(Constant.UNKNOWN);
        }
        bookingDetailsInfo.setLeadGuestTownCity(Constant.UNKNOWN);
        if (customerDTO.getCountry() == null) {
            bookingDetailsInfo.setLeadGuestCounty(Constant.UNKNOWN);
        } else {
            bookingDetailsInfo.setLeadGuestCounty(customerDTO.getCountry().getName());
        }
        bookingDetailsInfo.setLeadGuestPostcode(Constant.UNKNOWN);
        bookingDetailsInfo.setLeadGuestPhone(findTelephone(customerDTO.getTelephones(), PhoneTechType.VOICE));
        bookingDetailsInfo.setLeadGuestFax(findTelephone(customerDTO.getTelephones(), PhoneTechType.FAX));
        bookingDetailsInfo.setLeadGuestEmail(createEmail(customerDTO.getEmails()));
        bookingDetailsInfo.setRequest(createRequest(roomStayDTO.getSpecialRequests()));

        return bookingDetailsInfo;
    }

    private BigDecimal getTotal(TotalDTO total) {
        if (total == null) {
            throw new InvalidFieldException("total", "null");
        }

        if (total.getTotalAmount() == null) {
            throw new InvalidFieldException("totalAmount", "null");
        }

        if (total.getTotalAmount().getCurrency() != Currency.GBP) {
            throw new InvalidFieldException("currency", total.getTotalAmount().getCurrency().name());
        }

        return total.getTotalAmount().getAmount();
    }


    private String findReservationID(List<HotelReservationIDDTO> hotelReservationIDs, UniqueIDType uniqueIDType) {
        for (HotelReservationIDDTO hotelReservationID : hotelReservationIDs) {
            if (hotelReservationID.getResIDType() == uniqueIDType) {
                return hotelReservationID.getResIDValue();
            }
        }
        return "";
    }

    private String createRequest(List<SpecialRequestDTO> specialRequests) {
        StringBuilder builder = new StringBuilder();
        for (SpecialRequestDTO specialRequest : specialRequests) {
            builder.append(specialRequest.getText()).append("\r\n");
        }
        return builder.toString();
    }

    private String createEmail(List<EmailDTO> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            return StringUtils.trimToNull(emails.get(0).getValue());
        }
        return null;
    }

    private String findTelephone(List<TelephoneDTO> telephones, PhoneTechType phoneTechType) {
        for (TelephoneDTO telephone : telephones) {
            if (telephone.getTechType() == phoneTechType) {
                return telephone.getNumber();
            }
        }
        return "";
    }

    private ArrayOfRoomBooking createRoomBookings(HotelReservationDTO hotelReservationDTO) {
        ReservationRoomStayDTO roomStayDTO = hotelReservationDTO.getRoomStays().get(0);
        ArrayOfRoomBooking arrayOfRoomBooking = new ArrayOfRoomBooking();
        ReservationRoomStayDTO reservationRoomStayDTO = hotelReservationDTO.getRoomStays().get(0);
        for (int roomIndex = 0; roomIndex < reservationRoomStayDTO.getNumberOfUnits(); roomIndex++) {
            arrayOfRoomBooking.getRoomBooking().add(
                    createRoomBooking(roomIndex, roomStayDTO.getGuests(), reservationRoomStayDTO));

        }
        return arrayOfRoomBooking;
    }

    private RoomBooking createRoomBooking(int roomIndex, List<CustomerDTO> guests,
                                          ReservationRoomStayDTO reservationRoomStayDTO) {
        RoomBooking roomBooking = new RoomBooking();
        List<GuestCountDTO> guestCounts = reservationRoomStayDTO.getGuestCounts();
        roomBooking.setAdults(getGuestCount(guestCounts, AgeQualifyingType.ADULT));
        roomBooking.setChildren(getGuestCount(guestCounts, AgeQualifyingType.CHILD));
        roomBooking.setPropertyRoomTypeID(Integer.valueOf(reservationRoomStayDTO.getRoomTypeCode()));
        roomBooking.setMealBasisID(Integer.valueOf(reservationRoomStayDTO.getRatePlanCode()));

        ArrayOfGuest arrayOfGuest = new ArrayOfGuest();
        int guestCount = roomBooking.getAdults() + roomBooking.getChildren();
        for (int guestIndex = 0; guestIndex < guestCount; guestIndex++) {
            int index = (roomIndex * guestCount + guestIndex) % guests.size();
            arrayOfGuest.getGuest().add(createGuest(guests.get(index), guestIndex < roomBooking.getAdults()));
        }
        roomBooking.setGuests(arrayOfGuest);

        return roomBooking;
    }


    private Guest createGuest(CustomerDTO customerDTO, boolean isAdult) {
        Guest guest = new Guest();
        guest.setType(isAdult ? Constant.ADULT : Constant.CHILD);
        if (StringUtils.isNotEmpty(customerDTO.getPersonName().getNameTitle())) {
            guest.setTitle(customerDTO.getPersonName().getNameTitle());
        } else {
            guest.setTitle(Constant.TITLE);
        }
        guest.setFirstName(customerDTO.getPersonName().getGivenName());
        guest.setLastName(customerDTO.getPersonName().getSurname());
        guest.setAge(isAdult ? 0 : 10);
        return guest;
    }
}
